package com.to8to.scene.stat;

import static com.to8to.scene.server.Commons.mongo;
import static com.to8to.thrift.diary.module.TComment._Fields.STATUS;
import static com.to8to.thrift.diary.module.TProduct._Fields.TOTAL_PRICE;
import static com.to8to.thrift.diary.module.TScene._Fields.COVER_IMAGE;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.IMAGE_MAP;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.IMAGE_NUM;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.OWNER_COUNTS;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.OWNER_TYPE;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.PRODUCT_NUM;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.PRODUCT_PRICE;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.PROG_STAT_COUNTS;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.RECENT_DIARY_TIME;
import static com.to8to.thrift.diary.module.TSceneStat._Fields.SCENE_ID;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.to8to.commons.utils.StringUtil;
import com.to8to.commons.utils.ThriftUtil;
import com.to8to.scene.server.Commons;
import com.to8to.scene.server.Tables;
import com.to8to.thrift.diary.consts.constConstants;
import com.to8to.thrift.diary.module.TDiary;
import com.to8to.thrift.diary.module.TDiaryStat;
import com.to8to.thrift.diary.module.TImage;
import com.to8to.thrift.diary.module.TScene;
import com.to8to.thrift.diary.module.TSceneStat;

/**
 * 目的是将之前分散的更新统计操作都统一处理，从机制上保证修改可控
 * @author alpha.ren
 *
 */
public class StatSceneUpdateEngine extends AbstractStatUpdate
{
    public static Logger logger = LoggerFactory.getLogger(StatSceneUpdateEngine.class);

    //	private StatUpdateIface diary_stat;

    @Override
    public void asyncUpdate(String scene_id)
    {

        BasicDBObject update_db = new BasicDBObject();

        BasicDBObject scene_db = (BasicDBObject) Commons.mongo.findById(Tables.Scene, scene_id);
        if (null == scene_db)
            return;

        TScene scene = ThriftUtil.dbObject2ThriftObject(scene_db, TScene.class);

        /* */
        int recent_time = scene.getUtime();
        int recent_event = 0;
        String recent_user = scene.getOwner_id();

        TImage cover_image = scene.getCover_image();

        /* Diary */
        List<TDiary> diary_list = new ArrayList<TDiary>();
        List<String> diary_ids = new ArrayList<String>();

        DBCursor diary_cursor =
            Commons.mongo.cursor(Tables.Diary, new BasicDBObject(TDiary._Fields.SCENE_ID.getFieldName(), scene_id), null, null, 0, 0);
        while (diary_cursor.hasNext())
        {
            DBObject diary_db = diary_cursor.next();
            if (null == diary_db)
                continue;
            TDiary diary = ThriftUtil.dbObject2ThriftObject(diary_db, TDiary.class);
            diary_list.add(diary);
        }

        Map<String, Integer> prog_stat_counts = new HashMap<String, Integer>();
        Map<String, Integer> owner_counts = new HashMap<String, Integer>();
        owner_counts.put("j", 0);
        owner_counts.put("y", 0);
        for (TDiary diary : diary_list)
        {
            /* trigger diary stat update */
            //			DBObject diary_db = diary_stast.asyncUpdate(diary.get_id());
            //			if(null==diary_db) continue;
            //			diary = ThriftUtil.dbObject2ThriftObject(diary_db, TDiary.class);

            /* prog_stat_counts */
            String prog_stat_key = diary.getProgress_id() + "_" + diary.getStatus();
            Integer prog_stat_count = prog_stat_counts.get(prog_stat_key);
            if (null == prog_stat_count)
                prog_stat_count = 1;
            else
                prog_stat_count++;
            prog_stat_counts.put(prog_stat_key, prog_stat_count);

            if (diary.getStatus() != constConstants.ENTITY_STATUS_NORM)
                continue;

            /* cover_image */
            List<TImage> images = diary.getImages();
            if ((null == cover_image) && diary.getImage_num() > 0)
                cover_image = images.get(0);

            /* owner_counts */
            // 还需要再判断一次吗？
            //			if(diary.getStatus() == constConstants.ENTITY_STATUS_NORM){
            int jianli_id = diary.getJianli_id();
            if (jianli_id > 0)
            {
                Integer jianli_count = owner_counts.get("j");
                jianli_count++;
                owner_counts.put("j", jianli_count);
            }
            else
            {
                Integer owner_count = owner_counts.get("y");
                owner_count++;
                owner_counts.put("y", owner_count);
            }
            //			}

            /* recent fields */
            TDiaryStat diary_stat = diary.getStat();
            if (diary_stat.getRecent_time() > recent_time)
            {
                recent_time = diary_stat.getRecent_time();
                recent_user = diary_stat.getRecent_user();
                recent_event = diary_stat.getRecent_event();
            }

            diary_ids.add(diary.get_id());
        }
        /* owner_type */
        int owner_type = 0;
        owner_type = calOwnerType(owner_counts);

        //		/* COMMENT */
        //		List<TComment> comment_list = new ArrayList(); 
        //		
        //		DBCursor comment_cursor = Commons.mongo.cursor(Tables.Comment, 
        //				new BasicDBObject(TComment._Fields.SCENE_ID.getFieldName(), scene_id),
        //				null,null,0,0);
        //		while(comment_cursor.hasNext()){
        //			DBObject comment_db = comment_cursor.next();
        //			if(null==comment_db) continue;
        //			// 【注】comment_cursor.next()会移动游标
        ////			TComment comment = ThriftUtil.dbObject2ThriftObject(comment_cursor.next(), TComment.class);
        //			TComment comment = ThriftUtil.dbObject2ThriftObject(comment_db, TComment.class);
        //			comment_list.add(comment);
        //		}
        //		/* comment_num */
        //		int comment_num = comment_list.size();
        //		for(TComment comment:comment_list){
        //			if(comment.getStatus()!=constConstants.ENTITY_STATUS_NORM) continue;
        //			/* recent fields */
        //			if(comment.getCtime()>recent_time){
        //				recent_time = comment.getCtime();
        //				recent_user = comment.getUser_id();
        //				recent_event = constConstants.RECENT_EVENT_COMMENT;
        //			}
        //		}
        //		
        //		/* PRODUCT */
        //		double product_price = 0;
        //		List<TProduct> product_list = new ArrayList(); 
        //		
        //		DBCursor product_cursor = Commons.mongo.cursor(Tables.Product, new BasicDBObject(TProduct._Fields.SCENE_ID.getFieldName(), scene_id), 
        //				null,null,
        //				0,0);
        //		while(product_cursor.hasNext()){	
        //			DBObject product_db = product_cursor.next();
        //			if(null==product_db) continue;
        ////			TProduct product = ThriftUtil.dbObject2ThriftObject(product_cursor.next(), TProduct.class);
        //			TProduct product = ThriftUtil.dbObject2ThriftObject(product_db, TProduct.class);
        //			if(product.getStatus()!=constConstants.ENTITY_STATUS_NORM) continue;
        //			product_list.add(product);
        //			product_price+=product.getTotal_price();
        //		}

        /* DBUpdate */
        String stat_prefix = TScene._Fields.STAT.getFieldName() + ".";
        update_db.put(TScene._Fields.COVER_IMAGE.getFieldName(), ThriftUtil.thriftObject2DBObject(cover_image));//这里错了，帮忙修复下
        update_db.put(stat_prefix + TSceneStat._Fields.PROG_STAT_COUNTS.getFieldName(), prog_stat_counts);
        update_db.put(stat_prefix + TSceneStat._Fields.OWNER_COUNTS.getFieldName(), owner_counts);
        //		update_db.put(stat_prefix+TSceneStat._Fields.COMMENT_NUM.getFieldName(), comment_list.size());
        //		update_db.put(stat_prefix+TSceneStat._Fields.PRODUCT_NUM.getFieldName(), product_list.size());
        //		update_db.put(stat_prefix+TSceneStat._Fields.PRODUCT_PRICE.getFieldName(), product_price);
        update_db.put(stat_prefix + TSceneStat._Fields.OWNER_TYPE.getFieldName(), owner_type);

        update_db.put(stat_prefix + TSceneStat._Fields.RECENT_EVENT.getFieldName(), recent_event);
        update_db.put(stat_prefix + TSceneStat._Fields.RECENT_TIME.getFieldName(), recent_time);
        update_db.put(stat_prefix + TSceneStat._Fields.RECENT_USER.getFieldName(), recent_user);

        //		return Commons.mongo.findAndModify(Tables.Scene,
        //				new BasicDBObject("_id", scene_id), 
        //				null,null, false, update_db, true, StatWriter.upset); 

        DBObject cond = new BasicDBObject("_id", scene_id);
        DBObject oper = new BasicDBObject("$set", update_db);
        mongo.update(Tables.Scene, cond, oper, false, false);
    }

    /**
     * 现场只有浏览和收藏两种行为
     * @param scene_id
     * @param behavior_type
     * @param status
     * @return
     */
    @Override
    public void syncUpdate(String scene_id, int behavior_type, int status)
    {
        BasicDBObject inc = new BasicDBObject();
        String behavior_num_name = "";

        switch (behavior_type)
        {
            case constConstants.BEHAVIOR_TYPE_VIEW:
            {
                behavior_num_name = TSceneStat._Fields.VIEW_NUM.getFieldName();
                break;
            }
            case constConstants.BEHAVIOR_TYPE_COLL:
            {
                behavior_num_name = TSceneStat._Fields.COLLECT_NUM.getFieldName();
                break;
            }
        }

        if (StringUtil.isEmpty(behavior_num_name))
        {
            return;
        }

        inc.put(TScene._Fields.STAT.getFieldName() + "." + behavior_num_name, status);
        BasicDBObject update = new BasicDBObject();
        update.put("$inc", inc);

        //		return Commons.mongo.findAndModify(Tables.Scene,
        //				new BasicDBObject(TScene._Fields._ID.getFieldName(),scene_id),
        //				null,null,false,
        //				update, true, false);

        DBObject cond = new BasicDBObject(TScene._Fields._ID.getFieldName(), scene_id);

        mongo.update(Tables.Scene, cond, update, false, false);
    }

    @Override
    public void refreshCommentInfo(String sceneId, int recentTime, String userId, boolean setRecent, boolean setCommentNum)
    {
        List<Integer> scene_stat_tgt_list;
        scene_stat_tgt_list = new ArrayList<Integer>();
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_SCENE);
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_DIARY);
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_PRODUCT);
        refreshCommentNum(Tables.Scene, sceneId, recentTime, userId, setRecent, setCommentNum, true, STAT_PREFIX
            + TSceneStat._Fields.COMMENT_NUM.getFieldName(), scene_stat_tgt_list);

        scene_stat_tgt_list = new ArrayList<Integer>();
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_SCENE);
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_DIARY);
        scene_stat_tgt_list.add(constConstants.TARGET_TYPE_PRODUCT);
        refreshCommentNum(Tables.Scene, sceneId, recentTime, userId, setRecent, setCommentNum, false, STAT_PREFIX
            + TSceneStat._Fields.REF_COMMENT_NUM.getFieldName(), scene_stat_tgt_list);
    }

    /**
     * 刷新现场有关商品的统计信息
     */
    @Override
    public void refreshProductInfo(String sceneId, int recentTime, String userId, boolean setRecent)
    {
        DBObject fields = new BasicDBObject(TOTAL_PRICE.getFieldName(), 1).append(STATUS.getFieldName(), 1);
        DBObject cond = new BasicDBObject(SCENE_ID.getFieldName(), sceneId);
        DBCursor cursor = mongo.cursor(Tables.Product, cond, fields, null, 0, 0);

        Map<Integer, Integer> productNum = new HashMap<Integer, Integer>();
        Map<Integer, Double> productPrice = new HashMap<Integer, Double>();

        while (cursor.hasNext())
        {
            DBObject dbObject = cursor.next();
            Object state = dbObject.get(STATUS.getFieldName());
            Object totalPrice = dbObject.get(TOTAL_PRICE.getFieldName());
            if (state != null && totalPrice != null)
            {
                double tp = Double.parseDouble(totalPrice.toString());
                Integer num = productNum.get(state);
                productNum.put(getInteger(state), num == null ? 1 : num + 1);
                Double price = productPrice.get(state);
                productPrice.put(getInteger(state), price == null ? tp : price + tp);
            }
        }

        // 设置商品总数和总价
        DBObject set =
            new BasicDBObject(STAT_PREFIX + PRODUCT_NUM.getFieldName(), productNum).append(STAT_PREFIX + PRODUCT_PRICE.getFieldName(), productPrice);

        DBObject oper = new BasicDBObject("$set", set);
        DBObject updateCond = new BasicDBObject("_id", sceneId);

        mongo.update(Tables.Scene, updateCond, oper, false, false);
    }

    /**
     * 判断现场是否存在封面
     */
    public boolean hasCoverImage(String sceneId)
    {
        // 查看是否存在封面
        DBObject dbScene =
            mongo.findOne(Tables.Scene, new BasicDBObject("_id", sceneId), new BasicDBObject(TScene._Fields.COVER_IMAGE.getFieldName(), 1), null);

        if (null == dbScene)
        {
            return false;
        }

        Object coverImage = dbScene.get(TScene._Fields.COVER_IMAGE.getFieldName());

        return coverImage != null;
    }

    /**
     * 拼装现场的更新操作
     */
    public DBObject assemblyUpdate(List<TDiary> diaryList, boolean hasCoverImage)
    {

        Map<String, Integer> progStatCounts = new HashMap<String, Integer>();
        Map<String, Integer> ownerCounts = new HashMap<String, Integer>();
        //		Map<Integer, List<DBObject>> images = new HashMap<Integer, List<DBObject>>();
        Map<String, Integer> imageNum = new HashMap<String, Integer>();
        Map<String, List<TImage>> imageMap = new HashMap<String, List<TImage>>();
        TImage coverImage = null;
        int recent_diary_time = 0;

        for (TDiary diary : diaryList)
        {
            // 计算各阶段各状态下的日记数
            calProgressStateDiaryCount(progStatCounts, diary);

            // 组装各状态下的图集
            Integer inum = imageNum.get(Integer.toString(diary.getStatus()));
            imageNum.put(Integer.toString(diary.getStatus()), inum == null ? diary.getImagesSize() : inum + diary.getImagesSize());

            List<TImage> ilist = imageMap.get(Integer.toString(diary.getStatus()));
            if (null == ilist)
                ilist = new ArrayList<TImage>();
            if (null != diary.getImages())
                ilist.addAll(diary.getImages());
            imageMap.put(Integer.toString(diary.getStatus()), ilist.subList(0, Math.min(ilist.size(), constConstants.MAX_SHOW_IMAGE_NUM)));

            //             assemblyImage(images, imageNum, diary);

            // 下面的更新操作都只针对通过审核的日记
            if (diary.getStatus() != constConstants.ENTITY_STATUS_NORM)
                continue;

            // 查找封面
            if (!hasCoverImage)
            {
                if (diary.getImagesSize() > 0)
                {
                    // 取第一张图片作封面
                    coverImage = diary.getImages().get(0);
                    hasCoverImage = true;
                }
            }

            // 计算监理日记数，业主日记数
            calOwnerDiaryCount(ownerCounts, diary);

            // 算最新更新日记时间
            recent_diary_time = Math.max(recent_diary_time, diary.getCtime());
        }

        int ownerType = calOwnerType(ownerCounts);

        DBObject set = new BasicDBObject();

        TSceneStat scene_stat = new TSceneStat();
        set.put(STAT_PREFIX + PROG_STAT_COUNTS.getFieldName(), progStatCounts);
        set.put(STAT_PREFIX + OWNER_COUNTS.getFieldName(), ownerCounts);
        set.put(STAT_PREFIX + OWNER_TYPE.getFieldName(), ownerType);
        set.put(STAT_PREFIX + IMAGE_NUM.getFieldName(), imageNum);
        scene_stat.setImage_map(imageMap);

        DBObject scene_stat_db = ThriftUtil.thriftObject2DBObject(scene_stat);
        set.put(STAT_PREFIX + IMAGE_MAP.getFieldName(), scene_stat_db.get(IMAGE_MAP.getFieldName()));
        set.put(STAT_PREFIX + RECENT_DIARY_TIME.getFieldName(), recent_diary_time);
        //		set.put(STAT_PREFIX + IMAGES.getFieldName(), images);

        if (coverImage != null)
        {
            set.put(COVER_IMAGE.getFieldName(), ThriftUtil.thriftObject2DBObject(coverImage));
        }

        return set;
    }

    /**
     *  计算各阶段各状态下的日记数
     */
    private void calProgressStateDiaryCount(Map<String, Integer> progStatCounts, TDiary diary)
    {
        String progStatKey = diary.getProgress_id() + "_" + diary.getStatus();
        Integer progStatCount = progStatCounts.get(progStatKey);
        progStatCounts.put(progStatKey, progStatCount == null ? 1 : progStatCount + 1);
    }

    /**
     * 计算监理日记数，业主日记数
     */
    private void calOwnerDiaryCount(Map<String, Integer> ownerCounts, TDiary diary)
    {
        if (diary.getJianli_id() > 0)
        {
            Integer jianliCount = ownerCounts.get("j");
            ownerCounts.put("j", jianliCount == null ? 1 : jianliCount + 1);
        }
        else
        {
            Integer ownerCount = ownerCounts.get("y");
            ownerCounts.put("y", ownerCount == null ? 1 : ownerCount + 1);
        }
    }

    /**
     * 组装各状态下的图集
     */
    @Deprecated
    private void assemblyImage(Map<Integer, List<DBObject>> images, Map<Integer, Integer> imageCount, TDiary diary)
    {
        List<DBObject> is = images.get(diary.getStatus());
        if (is != null)
        {
            if (diary.getImagesSize() > 0)
            {
                is.addAll(diary.getImages().stream().map(ThriftUtil::thriftObject2DBObject).collect(Collectors.toList()));
            }
        }
        else
        {
            if (diary.getImagesSize() > 0)
            {
                is = diary.getImages().stream().map(ThriftUtil::thriftObject2DBObject).collect(Collectors.toList());
            }
        }
        if (is != null)
        {
            images.put(diary.getStatus(), is);
        }
        imageCount.put(diary.getStatus(), is == null ? 0 : is.size());
    }

    /**
     * 刷新日记相关信息
     */
    @Override
    public void refreshDiaryInfo(String sceneId, int recentTime, String userId, boolean setRecent)
    {
        boolean hasCoverImage = hasCoverImage(sceneId);

        // 查找所有的日记 
        DBObject cond = new BasicDBObject(TDiary._Fields.SCENE_ID.getFieldName(), sceneId);
        DBCursor diaryCursor = mongo.cursor(Tables.Diary, cond, null, null, 0, 0);
        List<TDiary> diaryList = ThriftUtil.listCursor(diaryCursor, TDiary.class);

        DBObject set = assemblyUpdate(diaryList, hasCoverImage);

        if (setRecent && recentTime > 0)
        {
            setRecent(set, constConstants.RECENT_EVENT_DIARY, recentTime, userId);

            //更新recent_diary字段 for company_top_diary 需求 陈韬 (fix by alpha 20150114)
            set.put(TSceneStat._Fields.RECENT_DIARY_TIME.getFieldName(), recentTime);
        }

        DBObject updateCond = new BasicDBObject("_id", sceneId);
        DBObject oper = new BasicDBObject("$set", set);
        mongo.update(Tables.Scene, updateCond, oper, false, false);
        logger.debug("update for set:{} on scene:{}", set, sceneId);
    }

    private int calOwnerType(Map<String, Integer> owner_counts)
    {
        // 接下来由owner_counts来计算
        Integer jianliDiaries = owner_counts.get("j");
        Integer ownerDiaries = owner_counts.get("y");
        if (ownerDiaries == null || ownerDiaries == 0)
        {
            if (jianliDiaries == null || jianliDiaries == 0)
            {
                return constConstants.SCENE_OWNER_EPT;
            }
            else
            {
                return constConstants.SCENE_OWNER_PJ;
            }
        }
        else
        {
            return constConstants.SCENE_OWNER_NPJ;
        }

    }
}
